#include <sstream>
#include "Message.hpp"
#include "../Kitchen.hpp"
#include "../Pizza.hpp"

namespace pizzeria {
namespace communication {

Message::Message() {
  mType = GET_STATUS;
  mData = NULL;
  mAllocatedRessources = false;
}

Message::Message(Type type, utils::ISerializable *data) {
  mType = type;
  mData = NULL;
  if (data != NULL)
    mData = data;
  mAllocatedRessources = false;
}

Message::Message(const Message& toCopy) {
  mType = toCopy.mType;
  mData = toCopy.mData;
  mAllocatedRessources = false;
}

Message::~Message() {
  if (mAllocatedRessources)
    delete mData;
}

Message &Message::operator =(const Message& toCopy) {
  if (this != &toCopy) {
    mType = toCopy.mType;
    mData = toCopy.mData;
  }
  return *this;
}

std::string Message::Serialize() const {
  std::ostringstream oss;
  std::string dataSerialized = mData->Serialize();

  oss.write(reinterpret_cast<const char *>(&mType), sizeof(mType));
  oss << dataSerialized;
  return oss.str();
}

void Message::Deserialize(const std::string &data) {
  std::istringstream iss(data);

  mData = NULL;
  if (mType == NEW_ORDER)
    mData = new pizzeria::Pizza;
  else if (mType == STATUS)
    mData = new pizzeria::Kitchen;
  mAllocatedRessources = true;
  if (mData && mType != GET_STATUS) {
    mData->Deserialize(data);
  }
}

const utils::ISerializable* Message::GetData() const {
  return mData;
}

Message::Type Message::GetType() const {
  return mType;
}

void Message::SetData(utils::ISerializable *data) {
  mData = data;
}

void Message::SetType(Type type) {
  mType = type;
}

size_t Message::GetSerializedSize() const {
  size_t sizeOfData = sizeof(mType);

  if (mType == GET_STATUS) {
    Kitchen kitchen;
    sizeOfData += kitchen.GetSerializedSize();
  }
  else if (mType == NEW_ORDER) {
    Pizza pizza;
    sizeOfData += pizza.GetSerializedSize();
  }
  return sizeOfData;
}

} /* !namespace communication */
} /* !namespace pizzeria */
